//
//  PagedScrollViewController.m
//  ScrollViews
//
//  Created by cygarm on 15/6/7.
//  Copyright (c) 2015年 cygarm. All rights reserved.
//

#import "PagedScrollViewController.h"

@interface PagedScrollViewController ()

@end

@implementation PagedScrollViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //    // 1
    /*
     首先, 设置pageImages数组. 之前向工程中添加了5张照片。这个数组会包含着5张图片
     */
    pageImages = [NSMutableArray arrayWithCapacity:5];
    [pageImages addObject:[UIImage imageNamed:@"photo1.png"]];
    [pageImages addObject:[UIImage imageNamed:@"photo2.png"]];
    [pageImages addObject:[UIImage imageNamed:@"photo3.png"]];
    [pageImages addObject:[UIImage imageNamed:@"photo4.png"]];
    [pageImages addObject:[UIImage imageNamed:@"photo5.png"]];
    //不能添加nil对象成员
//    [pageImages addObject:nil];
    NSUInteger pageCount = pageImages.count;
//    NSLog(@"pageImages.count=:%ul", pageImages.count);
    //
    //    // 2
    /*
     页面索引从0开始, 设置pageControl的第一页和总页数
     */
    self.pageControl.currentPage = 0;
    self.pageControl.numberOfPages = pageCount;
    
    //    // 3
    /*
     接下来, 设置pageViews，它包含UIImageView对象. 开始时还没有页面载入进来，我们使用nil对象占位-数组下标对应一个页面。
     之后会使用可选绑定检查页面是否已经加载。
     */
    for (int i=0; i < pageCount; ++i) {
        [pageViews addObject:nil];
    }
    //    // 4
    /*
     scrollView需要知道他的内容的尺寸。
     你需要一个支持水平的页面滚动（如果想使用竖直页面滚动也是很容易修改的）的scroll view，
     使用页面总数乘以pagesScrollViewSize的宽度的乘积作为scrollView的内容宽度，
     内容的高度与pagesScrollViewSize的高度相同。
     */
    CGSize pagesScrollViewSize = self.scrollView.frame.size;
    self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * (CGFloat)pageImages.count,
                                             pagesScrollViewSize.height);
    //    // 5
    /*
     在初始化是你需要显示某些页面，所以调用了loadVisiblePages方法, 之后我们会实现它.
     */
    [self loadVisiblePages];
}

- (void) loadPage:(int)page {
    if (page < 0 || page >= pageImages.count) {
        // 如果超出了页面显示的范围，什么也不需要做
        return;
    }
//    // 1
    /*
     首先, 使用可先绑定检查是否已经加载了视图，如果pageView包含UIImageView就什么也不需要做，忽略后续处理。
     */
    UIImageView *pageView = pageViews[page];
    if (pageView) {
        // 页面已经加载，不需要额外操作
    } else {
//        // 2
    /*
     如果pageView是nil就需要创建一个页面。 先计算出页面的frame大小。 
     它与scrollView具有相同的尺寸，y方向偏移为0，将页面尺寸乘以页面序号作为x方向(水平方向)的偏移量。
     */
        CGRect frame = self.scrollView.bounds;
        frame.origin.x = frame.size.width * (CGFloat)page;
        frame.origin.y = 0.0;
//        // 3
    /*
     创建新的UIImageView设置并添加到scrollView.
     */
        UIImageView *newPageView = [[UIImageView alloc]initWithImage:pageImages[page]];
        newPageView.contentMode = UIViewContentModeScaleAspectFit;
        newPageView.frame = frame;
        [self.scrollView addSubview:newPageView];
        
//        // 4
    /*
     最后, 使用新创建的newPageView替换原来的nil对象。
     这样如果需要再次加载这个页面，程序会进入if分支并且不需要额外的操作了,因为页面已经创建过了。
     */
        pageViews[page] = newPageView;
    }
}

/*
 这个函数会清理之前使用loadPage创建的一个页面，
 它首先检查pageViews数组中这个页面的对象是否是nil,
 如果不是nil就从scroll view中移除这个对象并把pageViews中对应页面再次设置成nil，表明这个页面已经清理完成.
 
 你问为什么要这么麻烦的使用延迟加载和清理页面？
 好的, 在本例中, 你在开始的时候加载所有的页面并没什么关系，因为一共只加载5个页面，这并不会消耗太多内存。
 但如果你有100个页面要加载，每张图5MB。
 如果你一次加载所有的页面这将会占用500MB的内存! 
 你的应用很快就会耗尽可用的内存空间并被操作系统杀死。
 延迟加载意味着你在给定时刻在内存里只有一定数量的页面。
 */
- (void) purgePage:(int)page {
    if (page < 0 || page >= pageImages.count) {
        // 如果超出要显示的范围，什么也不做
        return;
    }
    // 从scrollView中移除页面并重置pageViews容器数组响应页面
    UIImageView *pageView = [[UIImageView alloc]initWithImage:pageViews[page]];
    if (pageView) {
        [pageView removeFromSuperview];
        pageViews[page] = nil;
    }
}

/*
 这里先计算出scroll view当前所在的页面，更新pageControl然后加载和清理相关的页面。
 计算当前所在页面的方式有些可怕，但也没那么坏。你可以通过计算几个页面来确信这是正确的。
 (注意floor()函数会取里传入的值最近的最小整数)
 
 你预先加载当前页面和当前页面相邻的页面。
 因此当用户开始滚动页面的时候用户可以在下一个页面居中的时候可以看到下一个页面。
 如果你想的话你也可以加载前后两个甚至三个页面，但这除了增加内存外没有其他用处。
 */
- (void) loadVisiblePages {
    // 首先确定当前可见的页面
    CGFloat pageWidth = self.scrollView.frame.size.width;
    int page = (int)floor((self.scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0));
//    
    // 更新pageControl
    self.pageControl.currentPage = page;
//
    // 计算那些页面需要加载
    int firstPage = page - 1;
    int lastPage = page + 1;
//    
    // 清理firstPage之前的所有页面
    for (int index = 0; index < firstPage; ++index) {
        [self purgePage:index];
    }
//    
    // 加载范围内（firstPage到lastPage之间）的所有页面
    for (int index = firstPage; index <= lastPage; ++index) {
        [self loadPage:index];
    }
//    
    // 清理lastPage之后的所有页面
    for (int index = lastPage+1; index < pageImages.count; ++index) {
        [self purgePage:index];
    }
}

/*
 所有这些是为了确保当页面滚动完后相关的页面总会加载完毕(不需要的页面被清理完毕)。
 */
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
    // Load the pages that are now on screen
    [self loadVisiblePages];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end
